package com.demo.ocr.filtering;

/**
 * @author: 李德才
 * @description:
 * @create: 2021-06-06 16:28
 **/

import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.util.Objects;

import static com.demo.ocr.filtering.ImageUtil.readImg;
import static com.demo.ocr.filtering.ImageUtil.writeImg;

/**
 * *** 对称近邻均值滤波 ***
 *
 *  对称近邻（SNN：Symmetric Nearest Neighbor）均值滤波的核心思想是，
 *  在一个局部范围内，通过几对对称点像素的比较，获得相对区域及不同区域的差别，然后将均值计算在所判定的同一个区域内进行，
 *  这样可以使边界的保持更加灵活的同时又降低计算
 **/
public class SnnFiltering {

    public static void main(String[] args) {
        snnFiltering("F:\\OCR\\微信截图_20210605171455.png", "F:\\OCR\\微信截图_20210605171455-4.png", "png");
    }

    /**
     * 对称近邻均值滤波
     * @param srcPath 图片的存储位置
     * @param destPath 图像要保存的存储位置
     * @param format 图像要保存的存储位置
     */
    public static void snnFiltering(String srcPath, String destPath, String format) {
        BufferedImage img = readImg(srcPath);
        int w = Objects.requireNonNull(img).getWidth();
        int h = img.getHeight();
        int[] pix = new int[w*h];
        img.getRGB(0, 0, w, h, pix, 0, w);
        int[] newpix = snnFiltering(pix, w, h);
        img.setRGB(0, 0, w, h, newpix, 0, w);
        writeImg(img, format, destPath);
    }
    /**
     * 对称近邻均值滤波
     * @param pix 像素矩阵数组
     * @param w 矩阵的宽
     * @param h 矩阵的高
     * @return 处理后的数组
     */
    public static int[] snnFiltering(int[] pix, int w, int h) {
        int[] newPix = new int[w*h];
        int n = 9;
        int temp, i1,i2, sum;
        int[] temp1 = new int[n];
        int[] temp2 = new int[n/2];
        ColorModel cm = ColorModel.getRGBdefault();
        int r=0;
        for(int y=0; y<h; y++) {
            for(int x=0; x<w; x++) {
                if(x!=0 && x!=w-1 && y!=0 && y!=h-1) {
                    sum = 0;
                    temp1[0] = cm.getRed(pix[x-1+(y-1)*w]);
                    temp1[1] = cm.getRed(pix[x+(y-1)*w]);
                    temp1[2] = cm.getRed(pix[x+1+(y-1)*w]);
                    temp1[3] = cm.getRed(pix[x-1+(y)*w]);
                    temp1[4] = cm.getRed(pix[x+(y)*w]);
                    temp1[5] = cm.getRed(pix[x+1+(y)*w]);
                    temp1[6] = cm.getRed(pix[x-1+(y+1)*w]);
                    temp1[7] = cm.getRed(pix[x+(y+1)*w]);
                    temp1[8] = cm.getRed(pix[x+1+(y+1)*w]);
                    for(int k=0; k<n/2; k++) {
                        i1 = Math.abs(temp1[n/2] - temp1[k]);
                        i2 = Math.abs(temp1[n/2] - temp1[n-k-1]);
                        temp2[k] = i1<i2 ? temp1[k] : temp1[n-k-1];	//选择最接近原像素值的一个邻近像素
                        sum = sum + temp2[k];
                    }
                    r = sum/(n/2);
                    newPix[y*w+x] = 255<<24 | r<<16 | r<<8 |r;
                } else {
                    newPix[y*w+x] = pix[y*w+x];
                }
            }
        }
        return newPix;
    }
}
